

import java.io.*;
import java.util.Scanner;
import java.util.concurrent.atomic.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import dnamap.*;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.widgets.Composite;

public class MainWindow {
	
	private Shell sShell = null;  //  @jve:decl-index=0:visual-constraint="45,15"
	private Composite composite = null;
	private Composite composite1 = null;
	private StyledText styledText_input = null;
	private StyledText styledText_output = null;
	private Composite composite3 = null;
	private Button button_create = null;
	private Button button_save = null;
	private List list_endo = null;
	private Composite composite2 = null;
	private Button button_specify = null;
	private Combo combo_codon = null;
	private Label label = null;
	private Button button_about = null;
	private Composite composite5 = null;
	private String dnaSeq = null;  //  @jve:decl-index=0:
	private ProTrans proTrans;
	private String[] codonList;
	private int codonChoice;
	private int modTextF = 0;
	private int modCodF = 0;
	private int linecodon = 20;
	private int codonlen = 3;
	private int linelen = codonlen * linecodon;
	private java.util.List<RestrictionSite> restrictionList = null;
	private SeqSites[] synres = null;
	private CLabel cLabel = null;
	//  @jve:decl-index=0:
	/**
	 * This method initializes sShell	
	 *
	 */
  	private void createSShell() {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = 24;
		sShell = new Shell();
		sShell.setText("Endo Creator 1.0");
		createComposite();
		sShell.setLayout(gridLayout);
		createComposite1();
		sShell.setSize(new Point(670, 476));
	}

	/**
	 * This method initializes composite	
	 *
	 */
	private void createComposite() {
		GridData gridData41 = new GridData();
		gridData41.horizontalAlignment = GridData.CENTER;
		gridData41.grabExcessHorizontalSpace = true;
		gridData41.verticalAlignment = GridData.FILL;
		GridData gridData3 = new GridData();
		gridData3.horizontalAlignment = GridData.FILL;
		gridData3.grabExcessHorizontalSpace = true;
		gridData3.grabExcessVerticalSpace = true;
		gridData3.verticalAlignment = GridData.FILL;
		GridData gridData = new GridData();
		gridData.horizontalAlignment = GridData.FILL;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalSpan = 23;
		gridData.verticalAlignment = GridData.FILL;
		composite = new Composite(sShell, SWT.NONE);
		composite.setLayout(new GridLayout());
		composite.setLayoutData(gridData);
		label = new Label(composite, SWT.NONE);
		label.setText("Endonucleases");
		label.setLayoutData(gridData41);
		list_endo = new List(composite, SWT.MULTI | SWT.V_SCROLL);
		list_endo.setLayoutData(gridData3);
		AtomicReference<List> ref = new AtomicReference<List>(list_endo);
		addRestriction("endonuclease.txt", ref);
		createComposite2();
		createCombo_codon();
		createComposite5();
	}

	/**
	 * This method initializes composite1	
	 *
	 */
	private void createComposite1() {
		GridData gridData4 = new GridData();
		gridData4.horizontalAlignment = GridData.FILL;
		gridData4.verticalSpan = 26;
		gridData4.grabExcessHorizontalSpace = true;
		gridData4.grabExcessVerticalSpace = true;
		gridData4.verticalAlignment = GridData.FILL;
		GridData gridData2 = new GridData();
		gridData2.horizontalAlignment = GridData.FILL;
		gridData2.grabExcessHorizontalSpace = true;
		gridData2.verticalSpan = 26;
		gridData2.grabExcessVerticalSpace = true;
		gridData2.verticalAlignment = GridData.FILL;
		GridData gridData1 = new GridData();
		gridData1.horizontalAlignment = GridData.FILL;
		gridData1.grabExcessHorizontalSpace = true;
		gridData1.grabExcessVerticalSpace = true;
		gridData1.verticalAlignment = GridData.FILL;
		composite1 = new Composite(sShell, SWT.NONE);
		composite1.setLayout(new GridLayout());
		composite1.setLayoutData(gridData1);
		styledText_input = new StyledText(composite1, SWT.V_SCROLL);
		styledText_input.setFont(new Font(Display.getDefault(), "Courier New", 9, SWT.NORMAL));
		styledText_input.setLayoutData(gridData2);		
		styledText_input.addModifyListener(new org.eclipse.swt.events.ModifyListener() {
			public void modifyText(org.eclipse.swt.events.ModifyEvent e) {
				// TODO Auto-generated Event stub modifyText()
				if(modTextF == 0)
				{
					modTextF = 1;	
					boolean ignoreInv = false;
					String tSeq = styledText_input.getText();
					String normSeq = "ATGCU";
					tSeq = tSeq.toUpperCase();
					String filterSeq = new String();
					for(int i = 0; i < tSeq.length(); i++)
					{
						if(normSeq.lastIndexOf(tSeq.charAt(i)) >= 0)
						{
							filterSeq += tSeq.charAt(i);
						}
						else
						{
							if((!ignoreInv) && (i < tSeq.length() - 1) && tSeq.charAt(i) != '\n')
							{
								MessageBox messageBox = new MessageBox(sShell, SWT.ICON_QUESTION
						            | SWT.YES | SWT.NO);
						        messageBox.setMessage("Invalid character in sequence\nRemove and continue?");
						        messageBox.setText("Invalid character present");
						        int response = messageBox.open();
						        if (response == SWT.NO)
						        {
						        	styledText_input.setText(dnaSeq);
						        	styledText_input.setCaretOffset(dnaSeq.length());
						        	modTextF = 0;
						        	return;
						        }	
						        ignoreInv = true;
							}
						}
					}
					dnaSeq = filterSeq;
					String showSeq = new String();
					for(int ptr = 0; ptr < dnaSeq.length(); ptr += linelen)
					{
						if(ptr + linelen < dnaSeq.length())
						{
							showSeq += dnaSeq.substring(ptr, ptr + linelen) + "\n";
						}
						else
						{
							showSeq += dnaSeq.substring(ptr);
						}
					}					
					styledText_input.setText(showSeq);
					styledText_input.setCaretOffset(showSeq.length());
					synres = new SeqSites[0];
					AtomicReference<StyledText> stRef =  new AtomicReference<StyledText>(styledText_output);
					synctranslate(stRef);
					modTextF = 0;
				}
			}
		});
		styledText_output = new StyledText(composite1, SWT.V_SCROLL);
		styledText_output.setFont(new Font(Display.getDefault(), "Courier New", 9, SWT.NORMAL));
		styledText_output.setLayoutData(gridData4);
		styledText_output.setEditable(false);
		createComposite3();
	}

	/**
	 * This method initializes composite3	
	 *
	 */
	private void createComposite3() {
		RowLayout rowLayout = new RowLayout();
		rowLayout.justify = true;
		rowLayout.fill = false;
		rowLayout.pack = true;
		rowLayout.wrap = false;
		rowLayout.type = org.eclipse.swt.SWT.HORIZONTAL;
		GridData gridData5 = new GridData();
		gridData5.horizontalAlignment = GridData.FILL;
		gridData5.grabExcessHorizontalSpace = true;
		gridData5.grabExcessVerticalSpace = false;
		gridData5.verticalAlignment = GridData.FILL;
		composite3 = new Composite(composite1, SWT.NONE);
		composite3.setLayoutData(gridData5);
		composite3.setLayout(rowLayout);
		button_create = new Button(composite3, SWT.NONE);
		button_create.setText("Create");
		button_create
				.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
					public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
						// TODO Auto-generated Event stub widgetSelected()
						int[] selectedIndices = list_endo.getSelectionIndices();
						java.util.List<RestrictionSite> siteList = new 
							java.util.ArrayList<RestrictionSite>();
						for(int i = 0; i < selectedIndices.length; i++)
						{
							siteList.add(restrictionList.get(selectedIndices[i]));
						}
						synMut(siteList);
					}
				});
		button_save = new Button(composite3, SWT.NONE);
		button_save.setText("Save File");
		button_save.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
			public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
				// TODO Auto-generated Event stub widgetSelected()
				FileDialog fd = new FileDialog(sShell, SWT.SAVE);
		        fd.setText("Save");		
		        fd.setFilterPath("C:/");
		        String[] filterExt = { "*.seq", "*.*" };
		        fd.setFilterExtensions(filterExt);
		        String selected = fd.open();
		        if(selected.length() > 0)
		        {
		        	saveSequence(selected);
		        }
			}
		});
		
		button_about = new Button(composite3, SWT.NONE);
		button_about.setText("About");
		button_about
				.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
					public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
						About about=new About();
						about.createSShell();
						//System.out.println("widgetSelected()"); // TODO Auto-generated Event stub widgetSelected()
					}
				});
	}

	/**
	 * This method initializes composite2	
	 *
	 */
	private void createComposite2() {
		RowLayout rowLayout1 = new RowLayout();
		rowLayout1.fill = false;
		rowLayout1.justify = true;
		GridData gridData6 = new GridData();
		gridData6.horizontalAlignment = GridData.FILL;
		gridData6.grabExcessHorizontalSpace = true;
		gridData6.verticalSpan = 5;
		gridData6.verticalAlignment = GridData.FILL;
		composite2 = new Composite(composite, SWT.NONE);
		composite2.setLayoutData(gridData6);
		composite2.setLayout(rowLayout1);
		/*button_specify = new Button(composite2, SWT.NONE);
		button_specify.setText("Specify");
		button_specify.setVisible(false);
		button_specify.addSelectionListener(new org.eclipse.swt.events.SelectionAdapter() {
			public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
				Specify_Endo specify= new Specify_Endo();
				specify.createSShell();
				System.out.println("widgetSelected()"); // TODO Auto-generated Event stub widgetSelected()
			}
		});*/
		cLabel = new CLabel(composite2, SWT.NONE);
		cLabel.setText("choose codon");
	}

	/**
	 * This method initializes combo_codon	
	 *
	 */
	private void createCombo_codon() {
		GridData gridData7 = new GridData();
		gridData7.horizontalAlignment = GridData.FILL;
		gridData7.grabExcessHorizontalSpace = true;
		gridData7.verticalAlignment = GridData.FILL;
		combo_codon = new Combo(composite, SWT.READ_ONLY);		
		combo_codon.setText("");
		combo_codon.setLayoutData(gridData7);
		combo_codon
				.addSelectionListener(new org.eclipse.swt.events.SelectionListener() {
					public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) {
						// TODO Auto-generated Event stub widgetSelected()
						int sindex = combo_codon.getSelectionIndex();
						if(sindex < 0 || sindex > codonList.length || modCodF == 1)
						{
							return;
						}
						if(sindex != codonChoice)
						{
							codonChoice = sindex;
							proTrans.enter(codonList[sindex]);
							AtomicReference<StyledText> st = new
								AtomicReference<StyledText>(styledText_output);
							synctranslate(st);
						}
					}
					public void widgetDefaultSelected(
							org.eclipse.swt.events.SelectionEvent e) {
					}
				});
		for(int i = 0; i < codonList.length; i++)
		{
			combo_codon.add(codonList[i].substring(0,
					codonList[i].lastIndexOf('.')));
		}
		combo_codon.select(0);
	}

	/**
	 * This method initializes composite5	
	 *
	 */
	private void createComposite5() {
		GridLayout gridLayout1 = new GridLayout();
		gridLayout1.verticalSpacing = 5;
		GridData gridData9 = new GridData();
		gridData9.horizontalAlignment = GridData.FILL;
		gridData9.grabExcessHorizontalSpace = true;
		gridData9.grabExcessVerticalSpace = false;
		gridData9.verticalSpan = 7;
		gridData9.verticalAlignment = GridData.FILL;
		composite5 = new Composite(composite, SWT.NONE);
		composite5.setLayoutData(gridData9);
		composite5.setLayout(gridLayout1);
	}

	/**
	 * @Initialize
	 */
	public MainWindow()
	{	
		codonList = new String[2];
		codonList[0] = "human.txt";
		codonList[1] = "ecoli.txt";
		codonChoice = 0;
		proTrans = new ProTrans(codonList[codonChoice]);
		dnaSeq = new String();
		synres = new SeqSites[0];
	}
	
	public static void main(String[] args) {
		MainWindow main = new MainWindow();
		Display display = new Display();
		main.proTrans = new ProTrans("human.txt");
		
		main.createSShell();
		main.sShell.open();
		while (!main.sShell.isDisposed()) {
			if (!display.readAndDispatch())
	        display.sleep();
	  }
	  //System.out.println("finishing...");
	  display.dispose();
	      // TODO Auto-generated method stub

	}
	private void saveSequence(String fname)
	{
		try
		{
			FileWriter fout = new FileWriter(new File(fname));
			if(dnaSeq == null)
			{
				dnaSeq = "\n";
			}
			fout.write(dnaSeq);
			fout.close();
		}
		catch(Exception e)
		{
			System.out.println("Unable to create file.");
		}
	}
	private String strrpt(String x, int num)
	{
		String res = new String();
		for(int i = 0; i < num; i++)
		{
			res += x;
		}
		return res;
	}
	private void synctranslate(AtomicReference<StyledText> ref)
	{
		DNASeq myframe = new DNASeq(dnaSeq);		
		String[] proSeq = new String[codonlen];
		String[] fullCod = new String[codonlen];
		for(int i = 0; i < codonlen; i++)
		{
			proSeq[i] = proTrans.translate(myframe.getframe(i));
		}
		//System.out.println(proSeq);
		String output = new String();
		for(int i = 0; i < dnaSeq.length(); i += linelen)
		{
			if(i + linelen < dnaSeq.length())
			{
				output += dnaSeq.substring(i, i + linelen);
			}
			else
			{
				output += dnaSeq.substring(i);				
				output += strrpt(" ", linelen - dnaSeq.substring(i).length());
			}
			output += "\n";
			if(synres != null)
			{
				System.out.println(synres.length);
				for(int j = 0; j <synres.length; j++)
				{
					for(int k = i; k < i + linelen; k++)
					{
						System.out.println(k);
						if(k < dnaSeq.length() && k < synres[j].sequence.length())
						{
							output += synres[j].sequence.charAt(k);							
						}
						else
						{
							output += " ";
						}
					}
					output += "\n";
				}
			}
			for(int k = 0; k < codonlen; k++)
			{
				if(i == 0)
				{
					output += strrpt(" ", k);
				}
				else
				{
					output += fullCod[k];
				}
				for(int j = i; j < i + linelen - k - 2; j+= codonlen)
				{
					if((j + k)/codonlen < proSeq[k].length())
					{						
						output += strrpt(" ", (codonlen - 1)/2) + 
							proSeq[k].charAt((j + k)/codonlen) + 
							strrpt(" ", codonlen - (codonlen - 1)/2 - 1);
					}
					else
					{
						output += strrpt(" ", codonlen);				
					}
				}
				if((i + linelen + k)/codonlen <= proSeq[k].length())
				{
					//fullCod[k] = "___";
					fullCod[k] = strrpt(" ", (codonlen - 1)/2) +
						proSeq[k].charAt((i + linelen + k)/codonlen - 1) + 
						strrpt(" ", codonlen - (codonlen - 1)/2 -1);
				}
				else
				{
					fullCod[k] = strrpt(" ", codonlen);
				}
				
				if(k > 0)
				{
					//System.out.printf("%d ",k);
					//System.out.println(fullCod[k]);
					output += fullCod[k].substring(0, codonlen - k);
					fullCod[k] = fullCod[k].substring(codonlen - k);					
				}
				else
				{
					fullCod[k] = "";
				}
				output += "\n";
			}
		}
		ref.get().setText(output);
		Device device = Display.getCurrent();
		
		for(int i = 0; i*linelen < dnaSeq.length(); i++)
		{
			StyleRange sr = new StyleRange(i*( linelen + 1)*
					(codonlen + 1 + synres.length) + 
					(linelen + 1) * (synres.length + 1),
					(linelen + 1)*(codonlen), null, null, SWT.BOLD);
			//System.out.println(sr.toString());
			sr.foreground = new Color(device, 255, 0, 0);
			ref.get().setStyleRange(sr);
			if(synres.length > 0)
			{							
				for(int j = 0; j < linelen; j++)
				{
					int pos = i * (linelen + 1) *
					(codonlen + 1 + synres.length) + j;
					for(int k = 0; k < synres.length; k++)
					{				
						if(output.charAt(pos) == 
							output.charAt(pos + (linelen + 1) * (1 + k)))
						{
							StyleRange nst = new StyleRange(pos + 
									(linelen + 1) * (1 + k), 1, 
									new Color(device, 255, 255, 250),
									null,
									//new Color(device, 0, 240, 0),
									 SWT.BOLD);							
							ref.get().setStyleRange(nst);
						}
					}
				}
			}
		}
	}
	private void addRestriction(String fname, AtomicReference<List> ref)
	{
		restrictionList = new java.util.ArrayList<RestrictionSite>();
		try
		{
			Scanner fsc = new Scanner(new File(fname));
			//System.out.println("entr");
			while(fsc.hasNext())
			{
				String rName = fsc.next();
				String rSite = fsc.next();				
				restrictionList.add(new RestrictionSite(rSite, rName));
				//System.out.println(rName);
				//sSystem.out.println(rSite);
				ref.get().add(rName);				
			}
			fsc.close();
		}
		catch(Exception e)
		{
			System.out.println(e.getMessage());
			System.out.println("Error read in");
			return;
		}
	}
	private void synMut(java.util.List<RestrictionSite> sites)
	{
		SeqSites[] tsynres = new SeqSites[sites.size()];
		int sitecount =0;
		Point sRange = styledText_input.getSelectionRange();		
		
		if(sRange.y <= 0)
		{
			sRange.x = 0;
			sRange.y = styledText_input.getText().length();
		}
		int tlen = sRange.y;
		for(int i = sRange.x; i <sRange.x + sRange.y; i++)
		{
			if(styledText_input.getText().charAt(i) == '\n')
			{
				tlen--;
			}
		}		
		String curseq = styledText_input.getTextRange(sRange.x, sRange.y);
		DNASeq curframe = new DNASeq(curseq);
		sRange.y = tlen;
		//System.out.println(curframe.nucleotide(0, 1000));
		char[] synframe = curframe.getframe(0).toCharArray();
		for(int i = 0; i < sites.size(); i++)
		{
			char[] siteseq = sites.get(i).getseq();			
			tsynres[i] = new SeqSites();
			tsynres[i] = proTrans.synmut(synframe, siteseq);
			if(tsynres[i].sitenum() > 0)
				sitecount++;
		}
		//System.out.println(sitecount);
		synres = new SeqSites[sitecount];
		if(sitecount <= 0)
		{
			return;
		}
		sitecount = 0;
		for(int i = 0; i < sites.size(); i++)
		{
			//System.out.println(synres[sitecount].toString());
			if(tsynres[i].sitenum() > 0)
			{
				synres[sitecount] = new SeqSites();
				DNASeq newseq = new DNASeq(tsynres[i].sequence, 0);
				System.out.println(sRange.x + sRange.y);
				System.out.println(dnaSeq.length());
				synres[sitecount].sequence = 
					new String(dnaSeq.substring(0, sRange.x) 
					+ newseq.nucleotide(0, newseq.length()) + 
					dnaSeq.substring(sRange.x + sRange.y));
				//System.out.println(synres[sitecount].sequence);
				sitecount++;				
			}
		}
		AtomicReference<StyledText> ref = new 
			AtomicReference<StyledText>(styledText_output);
		synctranslate(ref);
	}
}
